<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>Introduction - Zend Framework Manual</title>

    <link href="../css/shCore.css" rel="stylesheet" type="text/css" />
    <link href="../css/shThemeDefault.css" rel="stylesheet" type="text/css" />
    <link href="../css/styles.css" media="all" rel="stylesheet" type="text/css" />
</head>
<body>
<h1>Zend Framework</h1>
<h2>Programmer's Reference Guide</h2>
<ul>
    <li><a href="../en/zend.ldap.introduction.html">Inglês (English)</a></li>
    <li><a href="../pt-br/zend.ldap.introduction.html">Português Brasileiro (Brazilian Portuguese)</a></li>
</ul>
<table width="100%">
    <tr valign="top">
        <td width="85%">
            <table width="100%">
                <tr>
                    <td width="25%" style="text-align: left;">
                    <a href="zend.ldap.html">Zend_Ldap</a>
                    </td>

                    <td width="50%" style="text-align: center;">
                        <div class="up"><span class="up"><a href="zend.ldap.html">Zend_Ldap</a></span><br />
                        <span class="home"><a href="manual.html">Programmer's Reference Guide</a></span></div>
                    </td>

                    <td width="25%" style="text-align: right;">
                        <div class="next" style="text-align: right; float: right;"><a href="zend.ldap.api.html">API overview</a></div>
                    </td>
                </tr>
            </table>
<hr />
<div id="zend.ldap.introduction" class="section"><div class="info"><h1 class="title">Introduction</h1></div>
    

    <p class="para">
        <span class="classname">Zend_Ldap</span> is a class for performing <acronym class="acronym">LDAP</acronym>
        operations including but not limited to binding, searching and modifying entries
        in an <acronym class="acronym">LDAP</acronym> directory.
    </p>

    <div class="section" id="zend.ldap.introduction.theory-of-operations"><div class="info"><h1 class="title">Theory of operation</h1></div>
        

        <p class="para">
            This component currently consists of the main <span class="classname">Zend_Ldap</span> class,
            that conceptually represents a binding to a single <acronym class="acronym">LDAP</acronym> server
            and allows for executing operations against a <acronym class="acronym">LDAP</acronym> server such
            as OpenLDAP or ActiveDirectory (AD) servers. The parameters for binding may be
            provided explicitly or in the form of an options array.
            <span class="classname">Zend_Ldap_Node</span> provides an object-oriented interface
            for single <acronym class="acronym">LDAP</acronym> nodes and can be used to form a basis for an
            active-record-like interface for a <acronym class="acronym">LDAP</acronym>-based domain model.
        </p>

        <p class="para">
            The component provides several helper classes to perform operations on
            <acronym class="acronym">LDAP</acronym> entries (<span class="classname">Zend_Ldap_Attribute</span>) such as
            setting and retrieving attributes (date values, passwords, boolean values, ...), to
            create and modify <acronym class="acronym">LDAP</acronym> filter strings
            (<span class="classname">Zend_Ldap_Filter</span>) and to manipulate <acronym class="acronym">LDAP</acronym>
            distinguished names (DN) (<span class="classname">Zend_Ldap_Dn</span>).
        </p>

        <p class="para">
            Additionally the component abstracts <acronym class="acronym">LDAP</acronym> schema browsing
            for OpenLDAP and ActiveDirectoy servers <span class="classname">Zend_Ldap_Node_Schema</span>
            and server information retrieval for OpenLDAP-, ActiveDirectory- and Novell
            eDirectory servers (<span class="classname">Zend_Ldap_Node_RootDse</span>).
        </p>

        <p class="para">
            Using the <span class="classname">Zend_Ldap</span> class depends on the type of
            <acronym class="acronym">LDAP</acronym> server and is best summarized with some simple examples.
        </p>

        <p class="para">
            If you are using OpenLDAP, a simple example looks like the following
            (note that the <em class="emphasis">bindRequiresDn</em> option is important if you are
            <em class="emphasis">not</em> using AD):
        </p>

        <pre class="programlisting brush: php">
$options = array(
    &#039;host&#039;              =&gt; &#039;s0.foo.net&#039;,
    &#039;username&#039;          =&gt; &#039;CN=user1,DC=foo,DC=net&#039;,
    &#039;password&#039;          =&gt; &#039;pass1&#039;,
    &#039;bindRequiresDn&#039;    =&gt; true,
    &#039;accountDomainName&#039; =&gt; &#039;foo.net&#039;,
    &#039;baseDn&#039;            =&gt; &#039;OU=Sales,DC=foo,DC=net&#039;,
);
$ldap = new Zend_Ldap($options);
$acctname = $ldap-&gt;getCanonicalAccountName(&#039;abaker&#039;,
                                           Zend_Ldap::ACCTNAME_FORM_DN);
echo &quot;$acctname\n&quot;;
</pre>


        <p class="para">
            If you are using Microsoft AD a simple example is:
        </p>

        <pre class="programlisting brush: php">
$options = array(
    &#039;host&#039;                   =&gt; &#039;dc1.w.net&#039;,
    &#039;useStartTls&#039;            =&gt; true,
    &#039;username&#039;               =&gt; &#039;user1@w.net&#039;,
    &#039;password&#039;               =&gt; &#039;pass1&#039;,
    &#039;accountDomainName&#039;      =&gt; &#039;w.net&#039;,
    &#039;accountDomainNameShort&#039; =&gt; &#039;W&#039;,
    &#039;baseDn&#039;                 =&gt; &#039;CN=Users,DC=w,DC=net&#039;,
);
$ldap = new Zend_Ldap($options);
$acctname = $ldap-&gt;getCanonicalAccountName(&#039;bcarter&#039;,
                                           Zend_Ldap::ACCTNAME_FORM_DN);
echo &quot;$acctname\n&quot;;
</pre>


        <p class="para">
            Note that we use the  <span class="methodname">getCanonicalAccountName()</span> method
            to retrieve the account DN here only because that is what exercises the
            most of what little code is currently present in this class.
        </p>

        <div class="section" id="zend.ldap.introduction.theory-of-operations.automatic-username-canonicalization"><div class="info"><h1 class="title">Automatic Username Canonicalization When Binding</h1></div>
            

            <p class="para">
                If  <span class="methodname">bind()</span> is called with a non-DN username but
                <em class="emphasis">bindRequiresDN</em> is <b><tt>TRUE</tt></b> and no username in
                DN form was supplied as an option, the bind will fail. However, if a username in DN
                form is supplied in the options array, <span class="classname">Zend_Ldap</span> will
                first bind with that username, retrieve the account DN for the username
                supplied to  <span class="methodname">bind()</span> and then re-bind with that DN.
            </p>

            <p class="para">
                This behavior is critical to <a href="zend.auth.adapter.ldap.html" class="link"><span class="classname">Zend_Auth_Adapter_Ldap</span></a>,
                which passes the username supplied by the user directly to
                 <span class="methodname">bind()</span>.
            </p>

            <p class="para">
                The following example illustrates how the non-DN username
                &#039;<em class="emphasis">abaker</em>&#039; can be used with  <span class="methodname">bind()</span>:
            </p>

            <pre class="programlisting brush: php">
$options = array(
        &#039;host&#039;              =&gt; &#039;s0.foo.net&#039;,
        &#039;username&#039;          =&gt; &#039;CN=user1,DC=foo,DC=net&#039;,
        &#039;password&#039;          =&gt; &#039;pass1&#039;,
        &#039;bindRequiresDn&#039;    =&gt; true,
        &#039;accountDomainName&#039; =&gt; &#039;foo.net&#039;,
        &#039;baseDn&#039;            =&gt; &#039;OU=Sales,DC=foo,DC=net&#039;,
);
$ldap = new Zend_Ldap($options);
$ldap-&gt;bind(&#039;abaker&#039;, &#039;moonbike55&#039;);
$acctname = $ldap-&gt;getCanonicalAccountName(&#039;abaker&#039;,
                                           Zend_Ldap::ACCTNAME_FORM_DN);
echo &quot;$acctname\n&quot;;
</pre>


            <p class="para">
                The  <span class="methodname">bind()</span> call in this example sees that
                the username &#039;<em class="emphasis">abaker</em>&#039; is not in DN form, finds
                <em class="emphasis">bindRequiresDn</em> is <b><tt>TRUE</tt></b>, uses
                &#039;<strong class="command">CN=user1,DC=foo,DC=net</strong>&#039; and &#039;<em class="emphasis">pass1</em>&#039; to
                bind, retrieves the DN for &#039;<em class="emphasis">abaker</em>&#039;, unbinds and then rebinds
                with the newly discovered
                &#039;<strong class="command">CN=Alice Baker,OU=Sales,DC=foo,DC=net</strong>&#039;.
            </p>
        </div>

        <div class="section" id="zend.ldap.introduction.theory-of-operations.account-name-canonicalization"><div class="info"><h1 class="title">Account Name Canonicalization</h1></div>
            

            <p class="para">
                The <em class="emphasis">accountDomainName</em> and
                <em class="emphasis">accountDomainNameShort</em>
                options are used for two purposes: (1) they facilitate multi-domain
                authentication and failover capability, and (2) they are also used to
                canonicalize usernames. Specifically, names are canonicalized to the
                form specified by the <em class="emphasis">accountCanonicalForm</em> option.
                This option may one of the following values:
            </p>

            <table id="zend.ldap.using.theory-of-operation.account-name-canonicalization.table" class="doctable table"><div class="info"><caption><b>Options for accountCanonicalForm</b></caption></div>
                

                
                    <thead valign="middle">
                        <tr valign="middle">
                            <th>Name</th>
                            <th>Value</th>
                            <th>Example</th>
                        </tr>

                    </thead>


                    <tbody valign="middle" class="tbody">
                        <tr valign="middle">
                            <td align="left"><b><tt>ACCTNAME_FORM_DN</tt></b></td>
                            <td align="left">1</td>
                            <td align="left">CN=Alice Baker,CN=Users,DC=example,DC=com</td>
                        </tr>


                        <tr valign="middle">
                            <td align="left"><b><tt>ACCTNAME_FORM_USERNAME</tt></b></td>
                            <td align="left">2</td>
                            <td align="left">abaker</td>
                        </tr>


                        <tr valign="middle">
                            <td align="left"><b><tt>ACCTNAME_FORM_BACKSLASH</tt></b></td>
                            <td align="left">3</td>
                            <td align="left">EXAMPLE\abaker</td>
                        </tr>


                        <tr valign="middle">
                            <td align="left"><b><tt>ACCTNAME_FORM_PRINCIPAL</tt></b></td>
                            <td align="left">4</td>
                            <td align="left"><var class="filename">abaker@example.com</var></td>
                        </tr>

                    </tbody>
                
            </table>


            <p class="para">
                The default canonicalization depends on what account domain name options
                were supplied. If <em class="emphasis">accountDomainNameShort</em> was supplied, the
                default <em class="emphasis">accountCanonicalForm</em> value is
                <b><tt>ACCTNAME_FORM_BACKSLASH</tt></b>. Otherwise, if
                <em class="emphasis">accountDomainName</em> was supplied, the
                default is <b><tt>ACCTNAME_FORM_PRINCIPAL</tt></b>.
            </p>

            <p class="para">
                Account name canonicalization ensures that the string used to identify
                an account is consistent regardless of what was supplied to
                 <span class="methodname">bind()</span>. For example, if the user supplies an account
                name of <var class="filename">abaker@example.com</var> or just
                <em class="emphasis">abaker</em> and the <em class="emphasis">accountCanonicalForm</em>
                is set to 3, the resulting canonicalized name would be
                <em class="emphasis">EXAMPLE\abaker</em>.
            </p>
        </div>

        <div class="section" id="zend.ldap.introduction.theory-of-operations.multi-domain-failover"><div class="info"><h1 class="title">Multi-domain Authentication and Failover</h1></div>
            

            <p class="para">
                The <span class="classname">Zend_Ldap</span> component by itself makes no attempt
                to authenticate with multiple servers. However, <span class="classname">Zend_Ldap</span>
                is specifically designed to handle this scenario gracefully. The
                required technique is to simply iterate over an array of arrays of serve
                 options and attempt to bind with each server. As described above
                  <span class="methodname">bind()</span> will automatically canonicalize each name, so
                it does not matter if the user passes <var class="filename">abaker@foo.net</var> or
                <em class="emphasis">W\bcarter</em> or <em class="emphasis">cdavis</em> - the
                 <span class="methodname">bind()</span> method will only succeed if the credentials were
                successfully used in the bind.
            </p>

            <p class="para">
                Consider the following example that illustrates the technique required to
                implement multi-domain authentication and failover:
            </p>

            <pre class="programlisting brush: php">
$acctname = &#039;W\\user2&#039;;
$password = &#039;pass2&#039;;

$multiOptions = array(
    &#039;server1&#039; =&gt; array(
        &#039;host&#039;                   =&gt; &#039;s0.foo.net&#039;,
        &#039;username&#039;               =&gt; &#039;CN=user1,DC=foo,DC=net&#039;,
        &#039;password&#039;               =&gt; &#039;pass1&#039;,
        &#039;bindRequiresDn&#039;         =&gt; true,
        &#039;accountDomainName&#039;      =&gt; &#039;foo.net&#039;,
        &#039;accountDomainNameShort&#039; =&gt; &#039;FOO&#039;,
        &#039;accountCanonicalForm&#039;   =&gt; 4, // ACCT_FORM_PRINCIPAL
        &#039;baseDn&#039;                 =&gt; &#039;OU=Sales,DC=foo,DC=net&#039;,
    ),
    &#039;server2&#039; =&gt; array(
        &#039;host&#039;                   =&gt; &#039;dc1.w.net&#039;,
        &#039;useSsl&#039;                 =&gt; true,
        &#039;username&#039;               =&gt; &#039;user1@w.net&#039;,
        &#039;password&#039;               =&gt; &#039;pass1&#039;,
        &#039;accountDomainName&#039;      =&gt; &#039;w.net&#039;,
        &#039;accountDomainNameShort&#039; =&gt; &#039;W&#039;,
        &#039;accountCanonicalForm&#039;   =&gt; 4, // ACCT_FORM_PRINCIPAL
        &#039;baseDn&#039;                 =&gt; &#039;CN=Users,DC=w,DC=net&#039;,
    ),
);

$ldap = new Zend_Ldap();

foreach ($multiOptions as $name =&gt; $options) {

    echo &quot;Trying to bind using server options for &#039;$name&#039;\n&quot;;

    $ldap-&gt;setOptions($options);
    try {
        $ldap-&gt;bind($acctname, $password);
        $acctname = $ldap-&gt;getCanonicalAccountName($acctname);
        echo &quot;SUCCESS: authenticated $acctname\n&quot;;
        return;
    } catch (Zend_Ldap_Exception $zle) {
        echo &#039;  &#039; . $zle-&gt;getMessage() . &quot;\n&quot;;
        if ($zle-&gt;getCode() === Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH) {
            continue;
        }
    }
}
</pre>


            <p class="para">
                If the bind fails for any reason, the next set of server options is tried.
            </p>

            <p class="para">
                The  <span class="methodname">getCanonicalAccountName()</span> call gets the canonical
                account name that the application would presumably use to associate data with such
                as preferences. The <em class="emphasis">accountCanonicalForm = 4</em> in all server
                options ensures that the canonical form is consistent regardless of which
                server was ultimately used.
            </p>

            <p class="para">
                The special <b><tt>LDAP_X_DOMAIN_MISMATCH</tt></b> exception occurs when an
                account name with a domain component was supplied (e.g.,
                <var class="filename">abaker@foo.net</var> or <em class="emphasis">FOO\abaker</em> and not just
                <em class="emphasis">abaker</em>) but the domain component did not match either domain
                in the currently selected server options. This exception indicates
                that the server is not an authority for the account. In this
                case, the bind will not be performed, thereby eliminating unnecessary
                communication with the server. Note that the <em class="emphasis">continue</em>
                instruction has no effect in this example, but in practice for error handling and
                debugging purposes, you will probably want to check for
                <b><tt>LDAP_X_DOMAIN_MISMATCH</tt></b> as well as
                <b><tt>LDAP_NO_SUCH_OBJECT</tt></b> and
                <b><tt>LDAP_INVALID_CREDENTIALS</tt></b>.
            </p>

            <p class="para">
                The above code is very similar to code used within <a href="zend.auth.adapter.ldap.html" class="link"><span class="classname">Zend_Auth_Adapter_Ldap</span></a>.
                In fact, we recommend that you simply use that authentication adapter for
                multi-domain + failover <acronym class="acronym">LDAP</acronym> based authentication
                (or copy the code).
            </p>
        </div>
    </div>
</div>
        <hr />

            <table width="100%">
                <tr>
                    <td width="25%" style="text-align: left;">
                    <a href="zend.ldap.html">Zend_Ldap</a>
                    </td>

                    <td width="50%" style="text-align: center;">
                        <div class="up"><span class="up"><a href="zend.ldap.html">Zend_Ldap</a></span><br />
                        <span class="home"><a href="manual.html">Programmer's Reference Guide</a></span></div>
                    </td>

                    <td width="25%" style="text-align: right;">
                        <div class="next" style="text-align: right; float: right;"><a href="zend.ldap.api.html">API overview</a></div>
                    </td>
                </tr>
            </table>
</td>
        <td style="font-size: smaller;" width="15%"> <style type="text/css">
#leftbar {
	float: left;
	width: 186px;
	padding: 5px;
	font-size: smaller;
}
ul.toc {
	margin: 0px 5px 5px 5px;
	padding: 0px;
}
ul.toc li {
	font-size: 85%;
	margin: 1px 0 1px 1px;
	padding: 1px 0 1px 11px;
	list-style-type: none;
	background-repeat: no-repeat;
	background-position: center left;
}
ul.toc li.header {
	font-size: 115%;
	padding: 5px 0px 5px 11px;
	border-bottom: 1px solid #cccccc;
	margin-bottom: 5px;
}
ul.toc li.active {
	font-weight: bold;
}
ul.toc li a {
	text-decoration: none;
}
ul.toc li a:hover {
	text-decoration: underline;
}
</style>
 <ul class="toc">
  <li class="header home"><a href="manual.html">Programmer's Reference Guide</a></li>
  <li class="header up"><a href="manual.html">Programmer's Reference Guide</a></li>
  <li class="header up"><a href="reference.html">Zend Framework Reference</a></li>
  <li class="header up"><a href="zend.ldap.html">Zend_Ldap</a></li>
  <li class="active"><a href="zend.ldap.introduction.html">Introduction</a></li>
  <li><a href="zend.ldap.api.html">API overview</a></li>
  <li><a href="zend.ldap.usage.html">Usage Scenarios</a></li>
  <li><a href="zend.ldap.tools.html">Tools</a></li>
  <li><a href="zend.ldap.node.html">Object oriented access to the LDAP tree using Zend_Ldap_Node</a></li>
  <li><a href="zend.ldap.server.html">Getting information from the LDAP server</a></li>
  <li><a href="zend.ldap.ldif.html">Serializing LDAP data to and from LDIF</a></li>
 </ul>
 </td>
    </tr>
</table>

<script type="text/javascript" src="../js/shCore.js"></script>
<script type="text/javascript" src="../js/shAutoloader.js"></script>
<script type="text/javascript" src="../js/main.js"></script>

</body>
</html>